#include "pthread.h"
#include "fcntl.h"
#include "unistd.h"
#include "stdint.h"
#include "string.h"
#include "time.h"

#include "datapool_mutex.h"
#include "Dual_Link_List.h"

void* data_write_thread(void* arg)
{
	printf("&data_write_thread: data write thread started.\n");

	int file_des;
	ssize_t ret_val_write;
	int8_t ret_val_delete_node;
	int index = -1; // -1 is stand for header node
	int lock_ret_val, unlock_ret_val;
	p_ListNode p_node = NULL;
	p_ListNode p_node_to_delete = NULL;
	void* deleted_data = NULL;
	char* output_str = NULL;

	file_des = open("TestProject/Test_data/OutputData",
			O_RDWR | O_CREAT, 0666);
	if(-1 == file_des) {
		printf("&data_write_thread: Fail to open OutputData file.\n");
		pthread_exit(NULL);
	}

	lock_ret_val = pthread_mutex_lock(&mutex_list);
	if(0 != lock_ret_val) {
		printf("&data_write_thread: fail to lock mutex for data pool, "
				"data write thread exit.\n");
		pthread_exit(NULL);
	}

	p_node = p_list;

	while(1) {
#ifdef DEBUG
		printf("&data_write_thread: executed in the beginning of while\n");
#endif

		if( (p_list != p_node) && (NULL != get_additional_message(p_node)) ) {
			output_str = (char*)malloc(13);
			//output_str = (char*)malloc(strlen((char*)get_additional_message(p_node))+4);
#ifdef DEBUG
			printf("&data_write_thread: the output_str has been allocated %d bytes.\n", 
				strlen((char*)get_additional_message(p_node))+3);
#endif
			if(NULL == output_str) {
				printf("&data_write_thread: fail to allocate memory for output string, "
						"data write thread exit.\n");
				pthread_exit(NULL);
			}

			memset(output_str, 0, 13);
			strlen(output_str);
			output_str[0] = ((char*)get_data(p_node))[0];
			printf("&data_write_thread: Before cat, output_str is %s.\n", output_str);
			printf("&data_write_thread: Before cat, length of output_str is %d.\n", strlen(output_str));
			strcat(output_str, ": ");
			strcat(output_str, (char*)get_additional_message(p_node));
			if(NULL == output_str) {
				printf("&data_write_thread: Unable to get the infomation from the datapool."
						"data write thread exit.\n");
				pthread_exit(NULL);
			}

#ifdef DEBUG
			printf("&data_write_thread: %s has been readed from data pool.\n", output_str);
#endif

			ret_val_write = write(file_des, (void*)output_str, strlen(output_str));

#ifdef DEBUG
			printf("The length of the string to be wrote into output file is %d.\n",
				strlen(output_str));
#endif
			if(-1 == ret_val_write) {
				printf("&data_write_thread: Fail to write output data to Output file,"
						" data write thread exit.\n");
				pthread_exit(NULL);
			}

			free(output_str);
			free( get_data(get_node(p_list, index)) );
			ret_val_delete_node = delete_node_by_index(p_list, index, deleted_data);
			if(-1 == ret_val_delete_node) {
				printf("&data_write_thread: Fail to delete node in data pool, "
						"data process thread exit.\n");
				pthread_exit(NULL);
			}

#ifdef DEBUG
			printf("&data_write_thread: success to write a data to output file.\n");
#endif

			unlock_ret_val = pthread_mutex_unlock(&mutex_list);
			if(0 != unlock_ret_val) {
				printf("&data_write_thread: fail to unlock mutex for data pool, "
						"data write thread exit.\n");
				pthread_exit(NULL);
			}

			lock_ret_val = pthread_mutex_lock(&mutex_list);
			if(0 != lock_ret_val) {
				printf("&data_write_thread: fail to lock mutex for data pool, "
						"data write thread exit.\n");
				pthread_exit(NULL);
			}

			if(index == get_length(p_list)) {
				index = -1;
				p_node = p_list;
			}
			else {
				p_node = get_node(p_list, index);
				printf("&data_write_thread: index: %d after deleted.\n", index);
			}
		}
		else if(p_list == p_node) {
			printf("&data_write_thread: The data pool is empty, "
					"wait for 5 seconds.\n");
			unlock_ret_val = pthread_mutex_unlock(&mutex_list);
			if(0 != unlock_ret_val) {
				printf("&data_write_thread: fail to unlock mutex for data pool, "
						"data write thread exit.\n");
				pthread_exit(NULL);
			}

			sleep(5);

			lock_ret_val = pthread_mutex_lock(&mutex_list);
			if(0 != lock_ret_val) {
				printf("&data_write_thread: fail to lock mutex for data pool, "
					"data write thread exit.\n");
				pthread_exit(NULL);
			}

			if(0 == get_length(p_list)) {
				index = -1;
				p_node = p_list;
			}
			else {
				index = (index + 1) % get_length(p_list);
				p_node = get_node(p_list, index);
			}
		}
		else {
#ifdef DEBUG
			printf("&data_write_thread: This node has not been processed, skip for it.\n");
#endif
			unlock_ret_val = pthread_mutex_unlock(&mutex_list);
			if(0 != unlock_ret_val) {
				printf("&data_write_thread: fail to unlock mutex for data pool, "
						"data write thread exit.\n");
				pthread_exit(NULL);
			}
	
			lock_ret_val = pthread_mutex_lock(&mutex_list);
			if(0 != lock_ret_val) {
				printf("&data_write_thread: fail to lock mutex for data pool, "
					"data write thread exit.\n");
			pthread_exit(NULL);
			}

			index = (index+1) % get_length(p_list);
			p_node = get_node(p_list, index);
#ifdef DEBUG
			printf("The address of p_list is %x.\n", p_list);
			printf("The address of p_node is %x.\n", p_node);
#endif
		}

#ifdef DEBUG
		printf("&data_write_thread: index: %d\n", index);
		printf("&data_write_thread: the length of data pool: %d\n", get_length(p_list));
#endif
	}

	printf("&data_write_thread: data write thread exit.\n");
	return NULL;
}
